import json
import os
import signal
import numpy as np
from aStar import aStar
from attck import calcEnemy
from calcAnimal import calcAnimal
from calcDir import calcDir
from calcTarget import calcTarget
from checkTarget import checkTarget
from render import render
from utils import crd_2_3, crd_game_to_gird, crd_grid_to_game, homePos, is_intersect, larger_normalized_projection_signed, one_zero_map, parse_map

MOVES={
  (0,0):'STOP',
  (0, 1):'RIGHT',
  (0, -1):'LEFT',
  (1, 0):'DOWN',
  (-1, 0):'TOP'
}
PDIRS={
  1:(-1,0),
  2:(1,0),
  3:(0,-1),
  4:(0,1)
}
class Director:
  target=None
  routes=None
  mod='' # a抓捕 b 吃道具 c 回家 d 脱离 s 攻击模式
  oldPos=None
  def play(self,stat):
    map,player,buffs=pre_parse(stat)
    player_=[p for p in stat['playerStateVos'] if p['playerId']==stat['playerId']][0]
    speed10=player_['speed']==10
    prePos=self.oldPos
    self.oldPos=(player[0],player[1])
    if player_['impacted']:
      self.oldPos=None
      return 'STOP'
    # 吃道具
    if checkShoe(stat) :
      # 先吃鞋子
      shoe=[x for x in stat['propVos'] if x['type']==1]
      if self.mod!='b':
          x=shoe[0]['y']
          y=shoe[0]['x']
          w=shoe[0]['width']
          
          self.target=(x,y,w)
          self.mod='b'
          self.routes=aStar(map,crd_game_to_gird(player[:2]),crd_game_to_gird(self.target[:2]),speed10)
    elif checkBags(stat):
      # 判断是否要吃背包
      bags=[x for x in stat['propVos'] if x['type']==2]
      if  self.mod!='b':
          x=bags[0]['y']
          y=bags[0]['x']
          w=bags[0]['width']
          self.target=(x,y,w)
          self.mod='b'
          self.routes=aStar(map,crd_game_to_gird(player[:2]),crd_game_to_gird(self.target[:2]))
          print('吃背包')
    elif checkShovel(stat):
      shovels=[x for x in stat['propVos'] if x['type']==3]
      if self.mod!='b':
        x=shovels[0]['y']
        y=shovels[0]['x']
        w=shovels[0]['width']
        self.target=(x,y,w)
        self.mod='b'
        self.routes=aStar(map,crd_game_to_gird(player[:2]),crd_game_to_gird(self.target[:2]))
        print('吃铲子')
    # 攻击模式
    if attackMod(stat):
      self.mod='s'
      self.target,self.routes=calcEnemy(stat)
      print('攻击模式', self.target, self.routes)
    else:
      target_,routes_= calcAnimal(stat)
      if self.mod != 'c' and (goHomeAnimal(stat) or goHome(stat)):
        # 判断是否装满了动物
        self.target=(*homePos(map),100)
        self.routes=aStar(map,crd_game_to_gird(player[:2]),crd_game_to_gird(self.target[:2]),speed10)
        self.mod='c'
      elif (not self.target) \
        or (not self.routes) or len(self.routes)<2 \
        or self.mod=='a' \
        or is_intersect(player[:2],50,crd_grid_to_game(self.routes[-1],50),50,self.mod=='c') \
        or (self.mod=='b') and (not checkTarget(self.target,buffs)) \
        or self.mod=='b' and routes_ and len(routes_)<=2 and (not fillAnimal(stat)) :

        if not self.target or (not self.routes) or len(self.routes)==0 or routes_[-1]!=self.routes[-1] :
          self.target=target_
          self.routes=routes_
          self.mod='a'
          
          
    if not is_intersect(player[:2],50,crd_grid_to_game(self.routes[0],50),50):
      self.routes.pop(0)
    players_=[]
    for p in stat['playerStateVos']:
      # 预测和其他车辆当前位置和下一个位置是否会相撞
      if p['playerId']==stat['playerId'] or (self.mod=='s' and self.target[2]==p['playerId']):
        continue
      players_.append((p['y'], p['x']))
      b_mod=prePos==(player[0],player[1])
      if not p['impacted'] and (not b_mod):
        if p['teamColor']==player_['teamColor']:
          # 尽可能避免和队友相撞
          for dx,dy in MOVES.keys():
            if (dx,dy)!=(0,0):
              players_.append((p['y']+p['speed']*dx, p['x']+p['speed']*dy))
        else:
          dx,dy=PDIRS[p['movingDirect']]
          players_.append((p['y']+p['speed']*dx, p['x']+p['speed']*dy))
    
    
    dir=calcDir(map,player[:2],self.routes,player_['speed'],players_)
    if dir=='STOP':
      if self.routes and len(self.routes)>=2:
        map[self.routes[1][0],self.routes[1][1]]='E'
        self.routes=aStar(map,crd_game_to_gird(player[:2]),crd_game_to_gird(self.target[:2]),speed10)
      elif self.mod=='a':
        # 抓捕动物时会出现车和动物出现在同一格的情况
        dir= larger_normalized_projection_signed(player[:2],self.target[:2])
        if dir in MOVES:
          return MOVES[dir]
    return dir
  
  def reset(self):
    self.target=None
    self.routes=None
    self.mod=''



def pre_parse(stat):
  map=parse_map(stat)

  player=None
  players=[]
  
  for item in stat['playerStateVos']:
    obj=(item['y'],item['x'],item['movingDirect'],item['speed'])
    if item['playerId']==stat['playerId']:
      player=obj
    else:
      players.append(obj)
  
  buffers=[(item['y'],item['x'],item['width']) for item in stat['propVos']]
    
  return map,player,buffers


  
def renderMap(map,routes):
  for x,y in routes:
    map[x,y]='B'
  render(map)

def checkShoe(stat):
  shoes=[x for x in stat['propVos'] if x['type']==1]
  player=[p for p in stat['playerStateVos'] if p['playerId']==stat['playerId']][0]
  
  if len(shoes)==0:
    return False
  
  if 1 in player['holdingProps']:
    return False
  
  dis=[]
  map=parse_map(stat)
  x,y=crd_2_3((shoes[0]['y'], shoes[0]['x']))
  a_map=animalNum2_3(stat)
  end=crd_game_to_gird((shoes[0]['y'], shoes[0]['x']))
  
  if a_map[x][y]==0 and len(aStar(map, crd_game_to_gird((player['y'], player['x'])), end, False))>6:
    return False
  for p in stat['playerStateVos']:
    if p['teamColor']!=player['teamColor'] or (1 in  p['holdingProps']):
      continue
    start=crd_game_to_gird((p['y'], p['x']))
    routes=aStar(map, start, end, False)
    dis.append((len(routes), p['playerId']))
    
  dis=sorted(dis,key=lambda x:x[0])
  return dis[0][1]==stat['playerId']

def checkBags(stat):
  bags=[x for x in stat['propVos'] if x['type']==2]
  player=[p for p in stat['playerStateVos'] if p['playerId']==stat['playerId']][0]
  
  if len(bags)==0:
    return False
  
  if 2 in player['holdingProps']:
    return False
  
  if checkShoe(stat):
    return False
  dis=[]
  map=parse_map(stat)
  x,y=crd_2_3((bags[0]['y'], bags[0]['x']))
  a_map=animalNum2_3(stat)
  end=crd_game_to_gird((bags[0]['y'], bags[0]['x']))
  if a_map[x][y]==0 or len(aStar(map, crd_game_to_gird((player['y'], player['x'])), end, player['speed']==10))>7:
    return False
  for p in stat['playerStateVos']:
    if p['teamColor']!=player['teamColor'] or (2 in  p['holdingProps']):
      continue
    start=crd_game_to_gird((p['y'], p['x']))
    routes=aStar(map, start, end, player['speed']==10)
    dis.append((len(routes), p['playerId']))
    
  dis=sorted(dis,key=lambda x:x[0])
  return dis[0][1]==stat['playerId']
  
def checkShovel(stat):
  shovels=[x for x in stat['propVos'] if x['type']==3]
  player=[p for p in stat['playerStateVos'] if p['playerId']==stat['playerId']][0]
  
  if len(shovels)==0:
    return False
  
  if 3 in player['holdingProps']:
    return False
  
  map=parse_map(stat)
  start=crd_game_to_gird((player['y'], player['x']))
  end=crd_game_to_gird((shovels[0]['y'], shovels[0]['x']))
  routes=aStar(map, start, end, player['speed']==10)
  return len(routes)<=3
  
def bagNum(stat):
  player=[p for p in stat['playerStateVos'] if p['playerId']==stat['playerId']]
  return sum([1 for x in  player[0]['holdingProps'] if x==2])

def buffNum(stat,type):
  player=[p for p in stat['playerStateVos'] if p['playerId']==stat['playerId']]
  return sum([1 for x in  player[0]['holdingProps'] if x==type])

def goHome(stat):
  "淘汰倒计时快到了，判断是否优先回家"
  time_=stat['gameMills']
  one_min=60*1000
  player=[p for p in stat['playerStateVos'] if p['playerId']==stat['playerId']][0]
  last=one_min-(time_%(one_min))<=12*1000
  players=sorted(stat['playerStateVos'],key=lambda p:p['rank'])
  
  if last and len(player['carried']):
    if players[-1]['playerId']==stat['playerId']:
      return True
    if time_>=120*1000:
      return True
  return False

def attackMod(stat):
  "是否进入攻击模式"
  
  player=[p for p in stat['playerStateVos'] if p['playerId']==stat['playerId']][0]
  teams=sorted([p for p in stat['playerStateVos'] if p['teamColor']==player['teamColor']],key=lambda p:p['rank'])
  time_=stat['gameMills']
  one_min=60*1000
  last=one_min-(time_%(one_min))<=12*1000
  enemys=[p for p in stat['playerStateVos'] if p['teamColor']!=player['teamColor']]
  if len(enemys)==0:
    return False
 
  if teams[0]['playerId']!=player['playerId'] and time_>=120*1000 and len(player['carried'])==0:
    return True

  if last and len(player['carried'])==0 and player['playerId']==teams[-1]['playerId'] and player['holdingProps'] not in [1,2]:
    return True
  
  return False
  
def goHomeAnimal(stat):
  "抓到动物时是否立刻回家"
  player=[p for p in stat['playerStateVos'] if p['playerId']==stat['playerId']][0]
  carried=fillAnimal(stat)
  if carried:
    if checkShoe(stat):
      return False
    
    if checkBags(stat):
      return False  
    
    if checkShovel(stat):
      return False
    
    return True
    
  else: 
    return False

def fillAnimal(stat):
  "是否已经抓满动物了"
  player=[p for p in stat['playerStateVos'] if p['playerId']==stat['playerId']][0]
  carried=len(player['carried'])>=min(player['carrySize'],2)
  return carried

def animalNum2_3(stat):
  arr=np.zeros((2,3))
  for animal in stat['animalStateVos']:
    x,y=crd_2_3((animal['y'],animal['x']))
    if animal['type']==4:
      arr[x][y]+=2
    else:
      arr[x][y]+=1
  return arr
    